在 part 1 裡,有舉出一個 Datalog 查詢的例子:
[:find ?title
:where
[_ :movie/title ?title]]
其中 :find
這個詞,英文的語意跟 SQL 的 SELECT
也差不多,而且它們的右方都是要寫查詢的目標、對查詢的輸出的修飾。
真正不一樣的地方是在 :where
。在 SQL 裡也有 WHERE
,且在 WHERE
的右邊是寫要用來篩選資料列的條件。 前述的 where
語意, Datalog 也差不多。但是,這邊有兩個不同點:
FROM
來指定是哪一張表。:where
條件的寫法,看起來與 SQL 條件的寫法頗不一樣。要解釋這些不同點,我們就必須先來了解 Datomic 的資訊模型 (information model) 了。
當我們在想象 SQL 資料庫的資訊模型時,我們通常是想成如下圖:
而 Datomic 資料庫的資訊模型則非常地不同,我們要想成是,彷彿整個資料庫只有一張表,而這張表有五個欄位。
[<entity-id> <attribute> <value> <tx-id> <op>]
...
[ 167 :person/name "James Cameron" 102 true]
[ 234 :movie/title "Die Hard" 102 true]
[ 234 :movie/year 1987 102 true]
[ 235 :movie/title "Terminator" 102 true]
[ 235 :movie/director 167 102 true]
...
在上述這張表中,每一列都可稱之為資料原子 (datom)。
而五個欄位分別是:
該怎麼理解上述這種特殊的資訊模型呢?我們可以這樣子想象:
如果我們要把 SQL 資料庫裡的若干張資料表裡的資料,全數塞入一張 Datomic 資料表,那我們可以怎麼做呢?具體的步驟如下:
entity-id
, attribute
和 value
,又可簡稱為 EAV model。其中,entity-id
的資料型態是長整數、attribute
的資料型態為字串、value
的資料型態為二進位 (BLOB)。movie
表有一個 title
欄位,這個欄位之後要叫 :movie/title
movie table
[entity-id :moive/title :movie/year :movie/director]
...
[214748 "Terminator" 1987 "James Francis Cameron"]
=>
Datomic table
[<entity-id> <attribute> <value>]
...
[214748 :moive/title "Terminator"]
[214748 :moive/year 1987]
[214748 :moive/director "James Francis Cameron"]
如果讀者心裡覺得,呃,這個方式滿酷的,還是說我們使用 SQL 資料庫時,也可以考慮這樣子設計資料表綱要來儲存資料?
這個作法叫做 EAV model ,通常被視為是反模式 (anti-pattern)。然而,wordpress 裡儲存 user meta 資料表、post meta 資料表都是用 EAV model ,所以實務中還是有在使用。
Datomic 的資訊模型還比 EAV model 更複雜一些些,因為還多了交易編碼與操作兩個欄位。這兩個欄位相對容易解釋:
交易編碼
操作
true
或是 false
。true
表示,這個資料原子對應的事實存在;而 false
表示,這個資料原子對應的事實不存在。換言之,當我們要刪除資料時,我們就會寫入新的資料原子,而這些資料原子會對應到某些既有的資料原子,且它們的操作欄位為 false
。以下這個查詢是要找出,所有含有 :person/name
恰好為 "Ridley Scott"
的資料實體編碼。
[:find ?e
:where
[?e :person/name "Ridley Scott"]]
逐字逐句來解釋上述的查詢:
[?e :person/name "Ridley Scott"]
這個條件比對整個資料庫的內容,:where
子句裡的 ?e
是一個未知的變數。?e
。是不是跟 SQL 查詢也有一點像呢?先執行的部分是寫在下方的部分。